package com.xy_pro.xymanager.service;

import com.alibaba.fastjson.JSONObject;
import com.xy_pro.xymanager.auth.dto.LoginRequest;
import com.xy_pro.xymanager.auth.dto.LoginResponse;
import com.xy_pro.xymanager.auth.dto.ResultResponse;
import com.xy_pro.xymanager.auth.dto.WebChatLogin;
import com.xy_pro.xymanager.auth.security.JwtTokenProvider;
import com.xy_pro.xymanager.auth.security.UserDetailsImpl;
import com.xy_pro.xymanager.entity.UserEntity;
import com.xy_pro.xymanager.exception.AuthenticationException;
import com.xy_pro.xymanager.exception.PhoneUserNotFoundException;
import com.xy_pro.xymanager.exception.ServerException;
import com.xy_pro.xymanager.exception.UserInfoInValidateException;
import com.xy_pro.xymanager.repository.UserRepository;
import com.xy_pro.xymanager.validator.WXBizDataCrypt;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Service
@RequiredArgsConstructor
public class AuthService {

    private final AuthenticationManager authenticationManager;
    private final UserRepository userRepository;
    private final PasswordEncoder encoder;
    private final JwtTokenProvider tokenProvider;

    @Value("${wechat.app-id}")
    private String appId;

    @Value("${wechat.app-secret}")
    private String appSecret;

    @Value("${wechat.jwt-secret}")
    private String jwtSecret;

    @Autowired
    private RestTemplate restTemplate;

    public Logger logger = LoggerFactory.getLogger(this.getClass());

    //管理员登录
    @SneakyThrows
    public LoginResponse login(LoginRequest loginRequest) {
        // 验证用户名和密码
        try {
            if(loginRequest.getUsername() == null || loginRequest.getPassword() == null) {
//                throw new BadCredentialsException("用户名和密码不能为空！");
            }
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUsername(),
                            loginRequest.getPassword()
                    )
            );

            // 设置安全上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);
        UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
        String username = userPrincipal.getUsername();
            String jwt = tokenProvider.generateJwtToken(username);

            // 获取用户信息
            UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
            UserEntity user = userRepository.findById(userDetails.getId()).orElseThrow();
//
//            // 返回用户信息（不包含密码）
//            UserEntity userEntity = new UserEntity();
//            userEntity.setName(user.getName());
//            userEntity.setId(user.getId());
//            userEntity.setName(user.getName());
//            userEntity.setPhone(user.getPhone());
//            userEntity.setAge(user.getAge());

            LoginResponse loginResponse = new LoginResponse();
            loginResponse.setUserName(userDetails.getUsername());
            boolean isAdmin = userDetails.getAuthorities().stream()
                    .anyMatch(authority ->
                            authority.getAuthority().equals("ROLE_ADMIN"));
            if(isAdmin) {
                loginResponse.setToken(jwt);

                return loginResponse;
            } else {
                throw new AuthenticationException("只允许管理员权限访问！");
            }

        } catch (BadCredentialsException e){
            throw new AuthenticationException("用户名密码不正确");
        } catch (UsernameNotFoundException e){
            throw new AuthenticationException("用户名不存在");
        } catch (Exception e){
            throw new AuthenticationException("认证失败！" + e.getMessage());
        }
    }

    public LoginResponse loginWebChat(WebChatLogin webChatLogin) {
        try {
            Map<String, Object> sessionMap = getSessionKey(webChatLogin.getCode());
            if (sessionMap == null) {
                throw new UserInfoInValidateException("获取 session_key 失败");
            }

            String sessionKey = sessionMap.get("session_key").toString();
            String openid = sessionMap.get("openid").toString();
            logger.info("从微信获取到的session_key：{}, openId:{}", sessionKey, openid);

            // 2. 解密手机号
            WXBizDataCrypt crypt = new WXBizDataCrypt(appId, sessionKey);
            String decryptedData = crypt.decryptData(webChatLogin.getEncryptedData(), webChatLogin.getIv());
            JSONObject phoneJson = JSONObject.parseObject(decryptedData);
            String phoneNumber = phoneJson.getString("phoneNumber");

//            logger.info("=======")
            logger.info("=======从微信解析的phoneNumber:{}", phoneNumber);

            // 3. 查询或创建用户
            Optional<UserEntity> user = userRepository.findByPhone(phoneNumber);
            if(user.isPresent()) {
                /// /如果用户存在
                UserEntity userEntity = user.get();
                if(userEntity.getUserMiniOpenId() == null || userEntity.getUserMiniOpenId().isEmpty()){
                    /// /第一次登录，走绑定流程
                    userEntity.setUserMiniOpenId(openid);
                    userEntity.setLastLoginDate(new Date());
                    userRepository.save(userEntity);
                } else {
                    userEntity.setLastLoginDate(new Date());
                    userRepository.save(userEntity);
                }
                LoginResponse loginResponse = new LoginResponse();
                String jwt = tokenProvider.generateJwtToken(userEntity.getName());
                loginResponse.setUserName(userEntity.getName());
                loginResponse.setToken(jwt);
                return loginResponse;
            } else {
                /// 用户不存在
                throw new PhoneUserNotFoundException("没查到此手机号码，请联系机构管理员添加！");
            }
        } catch (PhoneUserNotFoundException e) {
            // 专门处理用户不存在的情况
            logger.warn("用户不存在: {}", e.getMessage());
            throw e; // 直接抛出或者包装成自定义的业务异常
        } catch (UserInfoInValidateException e) {
            // 处理获取session_key失败的情况
            logger.error("获取session_key失败: {}", e.getMessage());
            throw e;
        } catch (Exception e) {
//            e.printStackTrace();
            logger.error("internal server error {}", e.getMessage());
            throw new ServerException("服务器内部错误");
//             error("绑定手机号失败");
        }
    }

    @SneakyThrows
    public LoginResponse loginUser(LoginRequest loginRequest) {
        // 验证用户名和密码
        try {
            if(loginRequest.getUsername() == null || loginRequest.getPassword() == null) {
//                throw new BadCredentialsException("用户名和密码不能为空！");
            }
            Authentication authentication = authenticationManager.authenticate(
                    new UsernamePasswordAuthenticationToken(
                            loginRequest.getUsername(),
                            loginRequest.getPassword()
                    )
            );

            // 设置安全上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);
            UserDetailsImpl userPrincipal = (UserDetailsImpl) authentication.getPrincipal();
            String username = userPrincipal.getUsername();
            String jwt = tokenProvider.generateJwtToken(username);

            // 获取用户信息
            UserDetailsImpl userDetails = (UserDetailsImpl) authentication.getPrincipal();
            UserEntity user = userRepository.findById(userDetails.getId()).orElseThrow();
//
//            // 返回用户信息（不包含密码）
//            UserEntity userEntity = new UserEntity();
//            userEntity.setName(user.getName());
//            userEntity.setId(user.getId());
//            userEntity.setName(user.getName());
//            userEntity.setPhone(user.getPhone());
//            userEntity.setAge(user.getAge());

            LoginResponse loginResponse = new LoginResponse();
            loginResponse.setUserName(userDetails.getUsername());
            loginResponse.setToken(jwt);

            return loginResponse;

        } catch (BadCredentialsException e){
            throw new AuthenticationException("用户名密码不正确");
        } catch (UsernameNotFoundException e){
            throw new AuthenticationException("用户名不存在");
        } catch (Exception e){
            throw new AuthenticationException("认证失败！" + e.getMessage());
        }
    }

    /**
     * 通过 code 换取 session_key 和 openid
     *
     * @param code 登录凭证
     * @return session_key 和 openid
     */
    private Map<String, Object> getSessionKey(String code) {
        try {
            String url = String.format(
                    "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code",
                    appId, appSecret, code
            );

            HttpHeaders headers = new HttpHeaders();
            HttpEntity<String> entity = new HttpEntity<>(headers);

            ResponseEntity<String> response = restTemplate.exchange(
                    url,
                    HttpMethod.GET,
                    entity,
                    String.class
            );

            String result = response.getBody();
            if (result == null) {
                return null;
            }

            Map<String, Object> map = JSONObject.parseObject(result, HashMap.class);
            if (map.containsKey("errcode")) {
                int errcode = (int) map.get("errcode");
                if (errcode != 0) {
                    logger.error("微信接口错误: " + map.get("errmsg"));
                    return null;
                }
            }

            return map;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}
